using NICWebApi.Extensions.Caching.Interfaces;
using NICWebApi.Extensions.Caching.Options;

namespace NICWebApi.Extensions.Caching.Implementations;

/// <summary>
/// 基于内存的缓存服务实现
/// 提供高性能的内存缓存操作，支持过期时间和缓存统计
/// </summary>
public class MemoryCacheService : ISimpleCacheService
{
    // 内存缓存实例
    private readonly IMemoryCache _memoryCache;

    // 缓存键生成器
    private readonly ISimpleCacheKeyGenerator _keyGenerator;

    // 缓存选项
    private readonly CachingOptions _options;

    // 存储缓存键的并发字典
    private readonly ConcurrentDictionary<string, object> _keys;

    // 通配符转正则表达式的正则
    private static readonly Regex _patternRegex = new(@"\*|\?", RegexOptions.Compiled);

    /// <summary>
    /// 初始化内存缓存服务
    /// </summary>
    /// <param name="memoryCache">内存缓存</param>
    /// <param name="keyGenerator">缓存键生成器</param>
    /// <param name="options">缓存选项</param>
    public MemoryCacheService(
        IMemoryCache memoryCache,
        ISimpleCacheKeyGenerator keyGenerator,
        IOptions<CachingOptions> options)
    {
        _memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
        _keyGenerator = keyGenerator ?? throw new ArgumentNullException(nameof(keyGenerator));
        _options = options?.Value ?? new CachingOptions();
        _keys = new ConcurrentDictionary<string, object>();
    }

    /// <summary>
    /// 获取缓存值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public T Get<T>(string key)
    {
        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);

        // 尝试从缓存中获取值
        if (_memoryCache.TryGetValue(normalizedKey, out object value) && value is T typedValue)
        {
            return typedValue;
        }

        return default;
    }

    /// <summary>
    /// 异步获取缓存值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<T> GetAsync<T>(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(Get<T>(key));
    }

    /// <summary>
    /// 设置缓存值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="expiration"></param>
    /// <returns></returns>
    public bool Set<T>(string key, T value, int? expiration = null)
    {
        if (value == null)
        {
            return false;
        }

        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        // 获取过期时间，默认使用配置的默认过期时间
        var expirationSeconds = expiration ?? _options.DefaultExpirationSeconds;
        var cacheOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(expirationSeconds),
            Size = _options.SizeLimit
        };

        // 如果启用了统计，将键添加到字典中
        if (_options.EnableStatistics)
        {
            _keys.TryAdd(normalizedKey, null);
        }

        _memoryCache.Set(normalizedKey, value, cacheOptions);
        return true;
    }

    /// <summary>
    /// 异步设置缓存值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="expiration"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<bool> SetAsync<T>(string key, T value, int? expiration = null, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(Set(key, value, expiration));
    }

    /// <summary>
    /// 移除缓存值
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Remove(string key)
    {
        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);

        // 从缓存中移除键
        _memoryCache.Remove(normalizedKey);
        // 如果启用了统计，从字典中移除键
        if (_options.EnableStatistics)
        {
            _keys.TryRemove(normalizedKey, out _);
        }

        return true;
    }

    /// <summary>
    /// 异步移除缓存值
    /// </summary>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<bool> RemoveAsync(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(Remove(key));
    }

    /// <summary>
    /// 移除匹配模式下的缓存值
    /// </summary>
    /// <param name="pattern"></param>
    /// <returns></returns>
    public int RemoveByPattern(string pattern)
    {
        // 归一化模式
        var normalizedPattern = _keyGenerator.GeneratePatternKey(pattern);

        // 将通配符模式转换为正则表达式
        var regex = new Regex(ConvertPatternToRegex(normalizedPattern));
        // 获取匹配的键
        var keysToRemove = _keys.Keys.Where(k => regex.IsMatch(k)).ToList();

        // 移除匹配的键
        foreach (var key in keysToRemove)
        {
            _memoryCache.Remove(key);
            _keys.TryRemove(key, out _);
        }

        return keysToRemove.Count;
    }

    /// <summary>
    /// 异步移除匹配模式下的缓存值
    /// </summary>
    /// <param name="pattern"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<int> RemoveByPatternAsync(string pattern, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(RemoveByPattern(pattern));
    }

    /// <summary>
    /// 检查缓存中是否存在指定键
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Exists(string key)
    {
        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        return _memoryCache.TryGetValue(normalizedKey, out _);
    }

    /// <summary>
    /// 异步检查缓存中是否存在指定键
    /// </summary>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<bool> ExistsAsync(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(Exists(key));
    }

    /// <summary>
    /// 获取或设置缓存值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="valueFactory"></param>
    /// <param name="expiration"></param>
    /// <returns></returns>
    public T GetOrSet<T>(string key, Func<T> valueFactory, int? expiration = null)
    {
        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);

        // 尝试从缓存中获取值
        if (_memoryCache.TryGetValue(normalizedKey, out object value) && value is T typedValue)
        {
            return typedValue;
        }

        // 调用值工厂获取新值并设置到缓存中
        var newValue = valueFactory();
        if (newValue != null)
        {
            Set(normalizedKey, newValue, expiration);
        }

        return newValue;
    }

    /// <summary>
    /// 异步获取或设置缓存值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="valueFactory"></param>
    /// <param name="expiration"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> valueFactory, int? expiration = null, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        // 尝试从缓存中获取值
        if (_memoryCache.TryGetValue(normalizedKey, out object value) && value is T typedValue)
        {
            return typedValue;
        }

        // 异步调用值工厂获取新值并设置到缓存中
        var newValue = await valueFactory().ConfigureAwait(false);
        if (newValue != null)
        {
            await SetAsync(normalizedKey, newValue, expiration, token).ConfigureAwait(false);
        }

        return newValue;
    }

    /// <summary>
    /// 获取匹配模式下的缓存键
    /// </summary>
    /// <param name="pattern"></param>
    /// <returns></returns>
    public IEnumerable<string> GetKeysByPattern(string pattern)
    {
        // 归一化模式
        var normalizedPattern = _keyGenerator.GeneratePatternKey(pattern);
        // 将通配符模式转换为正则表达式
        var regex = new Regex(ConvertPatternToRegex(normalizedPattern));
        // 获取匹配的键
        return _keys.Keys.Where(k => regex.IsMatch(k));
    }

    /// <summary>
    /// 异步获取匹配模式下的缓存键
    /// </summary>
    /// <param name="pattern"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<IEnumerable<string>> GetKeysByPatternAsync(string pattern, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(GetKeysByPattern(pattern));
    }

    /// <summary>
    /// 清空内存缓存
    /// </summary>
    public void Clear()
    {
        _memoryCache.Dispose();
        _keys.Clear();
    }

    /// <summary>
    /// 异步清空内存缓存
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task ClearAsync(CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        Clear();
        return Task.CompletedTask;
    }

    /// <summary>
    /// 获取缓存键的过期时间
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public TimeSpan? GetExpiration(string key)
    {
        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        if (_memoryCache.TryGetValue(normalizedKey, out _))
        {
            return TimeSpan.FromSeconds(_options.DefaultExpirationSeconds);
        }
        return null;
    }

    /// <summary>
    /// 异步获取缓存键的过期时间
    /// </summary>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<TimeSpan?> GetExpirationAsync(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(GetExpiration(key));
    }

    /// <summary>
    /// 刷新缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="expiration"></param>
    /// <returns></returns>
    public bool Refresh(string key, int? expiration = null)
    {
        // 归一化缓存键
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        if (_memoryCache.TryGetValue(normalizedKey, out object value))
        {
            return Set(normalizedKey, value, expiration);
        }
        return false;
    }

    /// <summary>
    /// 异步刷新缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="expiration"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<bool> RefreshAsync(string key, int? expiration = null, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(Refresh(key, expiration));
    }

    /// <summary>
    /// 将通配符模式转换为正则表达式
    /// </summary>
    /// <param name="pattern">通配符模式</param>
    /// <returns>正则表达式</returns>
    private static string ConvertPatternToRegex(string pattern)
    {
        return "^" + _patternRegex.Replace(pattern, m => m.Value == "*" ? ".*" : ".") + "$";
    }
}